
#ifndef __UM_SP_SHARED_PTR_H
#define __UM_SP_SHARED_PTR_H

#include "shared_count.hpp"

namespace UM {

	namespace detail {

		template<class T> struct shared_ptr_traits
		{
			typedef T& reference;
		};

		template<> struct shared_ptr_traits<void>
		{
			typedef void reference;
		};

	}

inline void sp_enable_shared_from_this(...) {
}

template <class T>
class shared_ptr
{

public:

	typedef T		element_type;
	typedef T		value_type;
	typedef T*		pointer;
	typedef typename detail::shared_ptr_traits<T>::reference reference;

	shared_ptr(void) : px(0), pn() {
	}

	template <class Y>
	explicit shared_ptr(Y* p) : px(p), pn(p) {
		sp_enable_shared_from_this(this, p, p);
	}

	template<class Y, class D>
	shared_ptr(Y * p, D d): px(p), pn(p, d) {
		sp_enable_shared_from_this(this, p, p);
	}

	template<class Y, class D, class A>
	shared_ptr(Y * p, D d, A a): px(p), pn(p, d, a) {
		boost::detail::sp_enable_shared_from_this( this, p, p );
	}
	
	template <class Y>
	shared_ptr(const shared_ptr<Y>& other) : px(other.px), pn(other.pn) {
	}

	template <class Y>
	shared_ptr& operator=(const shared_ptr<Y>& other) {
		shared_ptr<T>(other).swap(*this);
		return *this;
	}

	T* operator->() const {
		return this->px;
	}

	T& operator*() const {
		return *this->px;
	}

	~shared_ptr(void) {
	}

	bool unique() const {
		return this->pn.unique();
	}

	long use_count() const {
		return this->pn.use_count();
	}

	void swap(shared_ptr<T>& other) {
		std::swap(this->px, other.px);
		this->pn.swap(other.pn);
	}

	bool operator==(T* other) {
		return this->px == other;
	}

	operator T*() {
		return this->px;
	}

private:

	T* px;
	shared_count pn;
};

} // namespace UM

#endif // __UM_SP_SHARED_PTR_H